package com.yupi.yupicturebackend.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.yupicturebackend.exception.BusinessException;
import com.yupi.yupicturebackend.exception.ErrorCode;
import com.yupi.yupicturebackend.exception.ThrowUtils;
import com.yupi.yupicturebackend.mapper.SpaceUserMapper;
import com.yupi.yupicturebackend.model.dto.spaceuser.SpaceUserAddRequest;
import com.yupi.yupicturebackend.model.dto.spaceuser.SpaceUserQueryRequest;
import com.yupi.yupicturebackend.model.entity.Space;
import com.yupi.yupicturebackend.model.entity.SpaceUser;
import com.yupi.yupicturebackend.model.entity.User;
import com.yupi.yupicturebackend.model.enums.SpaceRoleEnum;
import com.yupi.yupicturebackend.model.enums.SpaceTypeEnum;
import com.yupi.yupicturebackend.model.vo.SpaceUserVO;
import com.yupi.yupicturebackend.model.vo.SpaceVO;
import com.yupi.yupicturebackend.model.vo.UserVO;
import com.yupi.yupicturebackend.service.SpaceService;
import com.yupi.yupicturebackend.service.SpaceUserService;
import com.yupi.yupicturebackend.service.UserService;
import lombok.Synchronized;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class SpaceUserServiceImpl extends ServiceImpl<SpaceUserMapper, SpaceUser>
        implements SpaceUserService {

    @Resource
    private UserService userService;

    @Resource
    @Lazy
    private SpaceService spaceService;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Override
    public long addSpaceUser(SpaceUserAddRequest spaceUserAddRequest) {
        //参数校验,判断参数是否为空
        ThrowUtils.throwIf(spaceUserAddRequest == null, ErrorCode.PARAMS_ERROR);
        //创建SpaceUser对象
        SpaceUser spaceUser = new SpaceUser();
        //复制属性值入SpaceUserAddRequest对象中去
        BeanUtils.copyProperties(spaceUserAddRequest, spaceUser);
        //校验spaceUser对象,避免添加时部分字段变为空值
        validSpaceUser(spaceUser, true);
        Long userId = spaceUser.getUserId();
        Long spaceId = spaceUser.getSpaceId();
        //控制当前空间不能出现相同用户，对其进行校验
        String lock = String.valueOf(userId).intern();
        synchronized (lock) {
            Long spaceUserId = transactionTemplate.execute(status -> {
                boolean exists = this.lambdaQuery()
                        .eq(SpaceUser::getUserId, userId)
                        .eq(SpaceUser::getSpaceId, spaceId)
                        .exists();
                //如果当前空间中已经存在这个用户，则直接拒绝添加
                ThrowUtils.throwIf(exists, ErrorCode.OPERATION_ERROR, "当前空间已经存在这个用户，拒绝添加");
                //执行新增操作，插入数据库
                boolean result = this.save(spaceUser);
                //判断是否新增成功，如果失败，抛出异常
                ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
                return spaceUser.getId();
            });
            return Optional.ofNullable(spaceUserId).orElse(-1L);
        }
    }

    @Override
    public void validSpaceUser(SpaceUser spaceUser, boolean add) {
        //校验spaceUser是否为空，如果不为空抛出异常
        ThrowUtils.throwIf(spaceUser == null, ErrorCode.PARAMS_ERROR);
        // 创建时，空间 id 和用户 id 必填
        Long spaceId = spaceUser.getSpaceId();
        Long userId = spaceUser.getUserId();
        if (add) {
            ThrowUtils.throwIf(ObjectUtil.hasEmpty(spaceId, userId), ErrorCode.PARAMS_ERROR);
            User user = userService.getById(userId);
            ThrowUtils.throwIf(user == null, ErrorCode.NOT_FOUND_ERROR, "用户不存在");
            Space space = spaceService.getById(spaceId);
            ThrowUtils.throwIf(space == null, ErrorCode.NOT_FOUND_ERROR, "空间不存在");
        }
        // 校验空间角色
        String spaceRole = spaceUser.getSpaceRole();
        SpaceRoleEnum spaceRoleEnum = SpaceRoleEnum.getEnumByValue(spaceRole);
        if (spaceRole != null && spaceRoleEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间角色不存在");
        }
    }

    @Override
    public SpaceUserVO getSpaceUserVO(SpaceUser spaceUser, HttpServletRequest request) {
        //对象转成封装类
        SpaceUserVO spaceUserVO = SpaceUserVO.objToVo(spaceUser);
        //关联查询用户信息
        Long userId = spaceUserVO.getUserId();
        if (userId != null && userId > 0) {
            User user = userService.getById(userId);
            UserVO userVO = userService.getUserVO(user);
            spaceUserVO.setUser(userVO);
        }
        //关联查询
        Long spaceId = spaceUserVO.getSpaceId();
        if (spaceId != null && spaceId > 0) {
            Space space = spaceService.getById(spaceId);
            SpaceVO spaceVO = spaceService.getSpaceVO(space, request);
            spaceUserVO.setSpace(spaceVO);
        }
        return spaceUserVO;
    }

    @Override
    public List<SpaceUserVO> getSpaceVOList(List<SpaceUser> spaceUserList) {
        //1如果参数为空，直接返回空列表
        if (CollUtil.isEmpty(spaceUserList)) {
            return Collections.emptyList();
        }
        //2对象列表->封装对象列表
        List<SpaceUserVO> spaceUserVOList = spaceUserList.stream().map(SpaceUserVO::objToVo).collect(Collectors.toList());
        //3获取用户id和空间id的列表集合
        Set<Long> userIdSet = spaceUserList.stream().map(SpaceUser::getUserId).collect(Collectors.toSet());
        Set<Long> spaceIdSet = spaceUserList.stream().map(SpaceUser::getSpaceId).collect(Collectors.toSet());
        //4批量查询用户和空间表信息
        Map<Long, List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        Map<Long, List<Space>> spaceIdSpaceListMap = spaceService.listByIds(spaceIdSet).stream()
                .collect(Collectors.groupingBy(Space::getId));
        //5填充SpaceUserVO中的用户信息
        spaceUserVOList.forEach(spaceUserVO -> {
                    Long userId = spaceUserVO.getUserId();
                    Long spaceId = spaceUserVO.getSpaceId();
                    //填充用户信息
                    User user = null;
                    if (userIdUserListMap.containsKey(userId)) {
                        user = userIdUserListMap.get(userId).get(0);
                    }
                    spaceUserVO.setUser(userService.getUserVO(user));
                    //填充空间信息
                    Space space = null;
                    if (spaceIdSpaceListMap.containsKey(spaceId)) {
                        space = spaceIdSpaceListMap.get(spaceId).get(0);
                    }
                    spaceUserVO.setSpace(SpaceVO.objToVo(space));
                }
        );
        return spaceUserVOList;
    }

    @Override
    public QueryWrapper<SpaceUser> getQueryWrapper(SpaceUserQueryRequest spaceUserQueryRequest) {
        QueryWrapper<SpaceUser> queryWrapper = new QueryWrapper<>();
        //如何查询请求为空，直接返回空的queryWrapper
        if (spaceUserQueryRequest == null) {
            return null;
        }
        //否则就一个一个获取查询条件的参数
        Long id = spaceUserQueryRequest.getId();
        Long userId = spaceUserQueryRequest.getUserId();
        Long spaceId = spaceUserQueryRequest.getSpaceId();
        String spaceRole = spaceUserQueryRequest.getSpaceRole();
        //接下来构造查询条件
        queryWrapper.eq(ObjUtil.isNotEmpty(id), "id", id);
        queryWrapper.eq(ObjUtil.isNotEmpty(userId), "userId", userId);
        queryWrapper.eq(ObjUtil.isNotEmpty(spaceId), "spaceId", spaceId);
        queryWrapper.eq(ObjUtil.isNotEmpty(spaceRole), "spaceRole", spaceRole);
        return queryWrapper;
    }
}
